package com.wangzhe.builder;

import com.wangzhe.bean.Constants;
import com.wangzhe.bean.FieldInfo;
import com.wangzhe.bean.TableInfo;
import com.wangzhe.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 王哲
 * @ClassName BuilderMapperXml
 * @create 2023--六月--下午2:21
 * @Description 构造MapperXml类
 * @Version V1.0
 */
public class BuilderMapperXml {

    private static Logger logger = LoggerFactory.getLogger(BuilderMapperXml.class);

    private static final String SQLNAME = "base_column_list";
    private static final String RESULTMAP = "base_result_map";
    private static final String QUERYCONDITION = "base_query_condition";
    private static final String QUERYCONDITIONEXTEND = "base_query_condition_extend";
    private static final String QUERYCONDITIONCOMMON = "query_condition";

    public static void builderMapperXml(TableInfo tableInfo) {
        File folder = new File(Constants.MAPPER_XML_PACKAGE_PATH);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String beanName = tableInfo.getBeanName() + Constants.MAPPER_XML_SUFFIX;
        File file = new File(folder, beanName + ".xml");

        OutputStream os = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        try {
            os = new FileOutputStream(file);
            osw = new OutputStreamWriter(os, "utf-8");
            bw = new BufferedWriter(osw);

            //xml文件的头部
            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            bw.newLine();
            bw.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"");
            bw.newLine();
            bw.write("\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
            bw.newLine();

            //xml文件的mapper标签
            bw.write("<mapper namespace=\"" + Constants.MAPPER_PACKAGE + "." + tableInfo.getBeanName() + Constants.MAPPER_SUFFIX + "\">");
            bw.newLine();

            //resultMap
            bw.write("\t<!--实体映射-->");
            bw.newLine();
            bw.write("\t<resultMap id=\"" + RESULTMAP + "\" type=\"" + Constants.POJO_BASE + "." + tableInfo.getBeanName() + "\">");
            bw.newLine();

            //拿到主键
            FieldInfo fieldInfos = null;
            Map<String, List<FieldInfo>> primaryKeyMap = tableInfo.getKeyIndexMap();
            for (Map.Entry<String, List<FieldInfo>> stringListEntry : primaryKeyMap.entrySet()) {
                if ("PRIMARY".equals(stringListEntry.getKey())) {
                    List<FieldInfo> value = stringListEntry.getValue();
                    if (value.size() == 1) {
                        fieldInfos = value.get(0);
                        break;
                    }
                }
            }

            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                String key = "result";
                if (fieldInfos != null && fieldInfo.getPropertyName().equals(fieldInfos.getPropertyName())) {
                    key = "id";
                } else {
                    key = "result";
                }
                bw.write("\t\t<!--" + fieldInfo.getComment() + "-->");
                bw.newLine();
                bw.write("\t\t<" + key + " column =\"" + fieldInfo.getFieldName() + "\" property=\"" + fieldInfo.getPropertyName() + "\"/>");
                bw.newLine();
            }
            bw.write("\t</resultMap>");
            bw.newLine();
            bw.newLine();

            //动态sql字段
            bw.write("\t<!--动态sql字段-->");
            bw.newLine();
            bw.write("\t<sql id=\"" + SQLNAME + "\">");
            bw.newLine();
            bw.write("\t\t");
            StringBuilder sb = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                sb.append(fieldInfo.getFieldName() + ",");
            }
            bw.write(sb.toString().substring(0, sb.lastIndexOf(",")));
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();
            //动态sql字段结束

            //基础查询条件
            bw.write("\t<!--基础查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\"" + QUERYCONDITION + "\">");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                String sqlType = fieldInfo.getSqlType();
                if (ArrayUtils.contains(Constants.SQL_STRING_TYPES, sqlType)) {
                    bw.write("\t\t<if test=\"query." + fieldInfo.getPropertyName() + " != null and query." + fieldInfo.getPropertyName() + " != ''\">");
                    bw.newLine();
                    bw.write("\t\t\tand " + fieldInfo.getFieldName() + " = #{query." + fieldInfo.getPropertyName() + "}");
                    bw.newLine();
                    bw.write("\t\t</if>");
                    bw.newLine();
                } else {
                    bw.write("\t\t<if test=\"query." + fieldInfo.getPropertyName() + "!=null\">");
                    bw.newLine();
                    bw.write("\t\t\tand " + fieldInfo.getFieldName() + " = #{query." + fieldInfo.getPropertyName() + "}");
                    bw.newLine();
                    bw.write("\t\t</if>");
                    bw.newLine();
                }
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();
            //基础查询条件结束

            //扩展查询条件
            bw.write("\t<!--扩展查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\"" + QUERYCONDITIONEXTEND + "\">");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getExtendFieldInfo()) {
                String javaType = fieldInfo.getFieldJavaType();
                String sqlType = fieldInfo.getSqlType();
                StringBuilder sbsql = new StringBuilder();
                if ("String".equals(javaType)) {
                    if (sqlType != null && "Date".equals(sqlType)) {
                        if (fieldInfo.getPropertyName().endsWith(Constants.DB_SUFFIX_PARAM_START)) {
                            sbsql.append("<![CDATA[ and " + fieldInfo.getFieldName() + " >= str_to_date(#{query." + fieldInfo.getPropertyName() + "},'%Y-%m-%d')]]>");
                        } else {
                            sbsql.append("<![CDATA[ and " + fieldInfo.getFieldName() + " < date_sub(str_to_date(#{query." + fieldInfo.getPropertyName() + "},'%Y-%m-%d'),interval -1 day)]]>");
                        }
                    } else {
                        sbsql.append(" and " + fieldInfo.getFieldName() + " like concat('%', #{query." + fieldInfo.getPropertyName() + "},'%')");
                    }
                }
                bw.write("\t\t<if test=\"query." + fieldInfo.getPropertyName() + " != null and query." + fieldInfo.getPropertyName() + " != ''\">");
                bw.newLine();
                bw.write("\t\t\t" + sbsql);
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();
            //扩展查询条件结束

            //通用查询条件
            bw.write("\t<!--通用查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\"" + QUERYCONDITIONCOMMON + "\">");
            bw.newLine();
            bw.write("\t\t<where>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + QUERYCONDITION + "\"/>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + QUERYCONDITIONEXTEND + "\"/>");
            bw.newLine();
            bw.write("\t\t</where>");
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();
            //通用查询条件结束

            //查询集合
            bw.write("\t<!--查询集合-->");
            bw.newLine();
            bw.write("\t<select id=\"selectList\" resultMap=\"" + RESULTMAP + "\">");
            bw.newLine();
            bw.write("\t\tSELECT <include refid=\"" + SQLNAME + "\"/> FROM " + tableInfo.getTableName() + " <include refid=\"" + QUERYCONDITIONCOMMON + "\"/>");
            bw.newLine();
            bw.write("\t\t\t<if test=\"query.orderBy!=null\">order by ${query.orderBy}</if>");
            bw.newLine();
            bw.write("\t\t\t<if test=\"query.simplePage!=null\"> limit #{query.simplePage.start},#{query.simplePage.end}</if>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();
            //查询集合结束

            //查询数量
            bw.write("\t<!--查询数量-->");
            bw.newLine();
            bw.write("\t<select id=\"selectCount\" resultType=\"java.lang.Integer\">");
            bw.newLine();
            bw.write("\t\tSELECT count(1) FROM " + tableInfo.getTableName() + " <include refid=\"" + QUERYCONDITIONCOMMON + "\"/>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();
            //查询数量结束
            String beanPathName = Constants.POJO_BASE + "." + tableInfo.getBeanName();
            //插入(匹配有值的字段)
            bw.write("\t<!--插入(匹配有值的字段)-->");
            bw.newLine();
            bw.write("\t<insert id=\"insert\" parameterType=\"" + beanPathName + "\">");
            bw.newLine();

            FieldInfo autoIncrementFieldInfo = null;
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    autoIncrementFieldInfo = fieldInfo;
                    break;
                }
            }

            if (autoIncrementFieldInfo != null) {
                bw.write("\t\t<selectKey keyProperty=\"" + autoIncrementFieldInfo.getPropertyName() + "\" resultType=\"" + autoIncrementFieldInfo.getFieldJavaType()
                        + "\" order=\"AFTER\">");
                bw.newLine();
                bw.write("\t\t\tSELECT LAST_INSERT_ID()");
                bw.newLine();
                bw.write("\t\t</selectKey>");
                bw.newLine();
            }

            bw.write("\t\tINSERT INTO " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\" >");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + ",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\" >");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t #{ bean." + fieldInfo.getPropertyName() + " },");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();
            //插入(匹配有值的字段)结束

            //插入或更新(匹配有值的字段)
            bw.write("\t<!--插入或更新(匹配有值的字段)-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdate\" parameterType=\"" + beanPathName + "\">");
            bw.newLine();

            autoIncrementFieldInfo = null;
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    autoIncrementFieldInfo = fieldInfo;
                    break;
                }
            }

            if (autoIncrementFieldInfo != null) {
                bw.write("\t\t<selectKey keyProperty=\"" + autoIncrementFieldInfo.getPropertyName() + "\" resultType=\"" + autoIncrementFieldInfo.getFieldJavaType()
                        + "\" order=\"AFTER\">");
                bw.newLine();
                bw.write("\tSELECT LAST_INSERT_ID()");
                bw.newLine();
                bw.write("\t\t</selectKey>");
                bw.newLine();
            }

            bw.write("\t\tINSERT INTO " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\" >");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + ",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\" >");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t #{ bean." + fieldInfo.getPropertyName() + " },");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();

            bw.write("\t\ton DUPLICATE key update");
            bw.newLine();

            Map<String, String> tempMap = new HashMap<>();
            for (Map.Entry<String, List<FieldInfo>> stringListEntry : primaryKeyMap.entrySet()) {
                if ("PRIMARY".equals(stringListEntry.getKey())) {
                    List<FieldInfo> value = stringListEntry.getValue();
                    value.forEach(fieldInfo -> {
                        tempMap.put(fieldInfo.getFieldName(), fieldInfo.getFieldName());
                    });
                }
            }

            bw.write("\t\t<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">");
            bw.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {

                if (tempMap.get(fieldInfo.getFieldName()) != null) {
                    continue;
                }

                bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + "= VALUES(" + fieldInfo.getFieldName() + "),");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();

            //插入或更新(匹配有值的字段)结束


            //添加(批量插入)
            bw.write("\t<!--添加(批量插入)-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertBatch\" parameterType=\"" + beanPathName + "\">");
            bw.newLine();

            StringBuilder stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    continue;
                }
                stringBuilder.append(fieldInfo.getFieldName()).append(",");
            }
            String substring = stringBuilder.substring(0, stringBuilder.toString().lastIndexOf(","));
            bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "(" + substring + ")");
            bw.newLine();
            bw.write("\t\tVALUES");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"bean\" separator=\",\" >");
            bw.newLine();
            stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    continue;
                }
                stringBuilder.append("#{bean.").append(fieldInfo.getPropertyName()).append("},");
            }
            substring = stringBuilder.substring(0, stringBuilder.toString().lastIndexOf(","));
            bw.write("\t\t\t (" + substring + ")");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();
            //添加(批量插入)结束

            //批量插入或更新
            bw.write("\t<!--批量插入或更新-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\"" + beanPathName + "\">");
            bw.newLine();

            stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    continue;
                }
                stringBuilder.append(fieldInfo.getFieldName()).append(",");
            }
            substring = stringBuilder.substring(0, stringBuilder.toString().lastIndexOf(","));
            bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "(" + substring + ")");
            bw.newLine();
            bw.write("\t\tVALUES");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"bean\" separator=\",\">");
            bw.newLine();
            stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                if (fieldInfo.isAutoIncrement()) {
                    continue;
                }
                stringBuilder.append("#{bean.").append(fieldInfo.getPropertyName()).append("},");
            }
            substring = stringBuilder.substring(0, stringBuilder.toString().lastIndexOf(","));
            bw.write("\t\t\t (" + substring + ")");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();

            bw.write("\t\ton DUPLICATE key update");
            bw.newLine();
            stringBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                stringBuilder.append(fieldInfo.getFieldName()).append("=VALUES(").append(fieldInfo.getFieldName()).append("),");
            }
            substring = stringBuilder.substring(0, stringBuilder.toString().lastIndexOf(","));
            bw.write("\t\t" + substring);
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();
            //批量插入或更新结束

            //根据主键更新
            bw.write("\t<!--根据主键更新-->");
            bw.newLine();
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for (Map.Entry<String, List<FieldInfo>> stringListEntry : keyIndexMap.entrySet()) {
                List<FieldInfo> value = stringListEntry.getValue();

                Integer index = 0;
                sb = new StringBuilder();
                StringBuilder methodParam = new StringBuilder();
                for (FieldInfo fieldInfo : value) {
                    index++;
                    methodParam.append(fieldInfo.getFieldName() + " = #{" + fieldInfo.getPropertyName() + "}");
                    sb.append(StringUtils.upperCaseFirst(fieldInfo.getPropertyName()));
                    if (index < value.size()) {
                        sb.append("And");
                        methodParam.append(" and ");
                    }
                }
                bw.newLine();
                bw.write("\t<!-- 根据" + sb + "查询 -->");
                bw.newLine();
                bw.write("\t<select id=\"selectBy" + sb + "\" resultMap=\"" + RESULTMAP + "\" >");
                bw.newLine();
                bw.write("\t\tSELECT");
                bw.newLine();
                bw.write("\t\t\t<include refid=\"" + SQLNAME + "\" />");
                bw.newLine();
                bw.write("\t\tFROM " + tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\tWHERE ");
                bw.newLine();
                bw.write("\t\t\t" + methodParam);
                bw.newLine();
                bw.write("\t</select>");
                bw.newLine();
                bw.newLine();
                bw.write("\t<!-- 根据" + sb + "删除 -->");
                bw.newLine();
                bw.write("\t<delete id=\"deleteBy" + sb + "\" >");
                bw.newLine();
                bw.write("\t\tdelete from " + tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\tWHERE ");
                bw.newLine();
                bw.write("\t\t\t" + methodParam);
                bw.newLine();
                bw.write("\t</delete>");
                bw.newLine();
                bw.newLine();
                bw.write("\t<!-- 根据" + sb + "更新 -->");
                bw.newLine();
                bw.write("\t<update id=\"updateBy" + sb + "\" parameterType=\"" + beanPathName + "\">");
                bw.newLine();
                bw.write("\t\tupdate " + tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\t<set>");
                bw.newLine();

                for (FieldInfo fieldInfo : tableInfo.getFieldInfo()) {
                    bw.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + " != null\">");
                    bw.newLine();
                    bw.write("\t\t\t\t" + fieldInfo.getFieldName() + " = #{ bean." + fieldInfo.getPropertyName() + "},");
                    bw.newLine();
                    bw.write("\t\t\t</if>");
                    bw.newLine();
                }

                bw.write("\t\t</set>");
                bw.newLine();
                bw.write("\t\tWHERE ");
                bw.newLine();
                bw.write("\t\t\t" + methodParam);
                bw.newLine();
                bw.write("\t</update>");
                bw.newLine();
            }
            bw.write("\t<!--根据主键更新结束-->");
            bw.newLine();
            //根据主键更新结束

            //xml文件的尾部
            bw.write("</mapper>");
            bw.newLine();
            bw.newLine();

            bw.flush();
        } catch (Exception e) {
            logger.info("创建MapperXml失败:{}", e.getMessage());
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
                if (osw != null) {
                    osw.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
